package com.scs.application.modules.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.CacheUtils;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UtilNum;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrUnit;
import com.scs.application.modules.base.service.MatrService;
import com.scs.application.modules.base.service.MatrUnitService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.dept.util.UtilBudget;
import com.scs.application.modules.finance.entity.Bill;
import com.scs.application.modules.finance.entity.BillItem;
import com.scs.application.modules.purchase.enums.PurchaseType;
import com.scs.application.modules.wm.dto.StockDTO;
import com.scs.application.modules.wm.dto.TraceBackDTO;
import com.scs.application.modules.wm.dto.TraceBackOrderDTO;
import com.scs.application.modules.wm.dto.WorkOrderItemDTO;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.enums.UniqueCodeType;
import com.scs.application.modules.wm.enums.WorkOrderType;
import com.scs.application.modules.wm.mapper.WorkOrderMapper;
import com.scs.application.modules.wm.service.*;
import com.scs.application.modules.wm.utils.StockCommonService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * WorkOrder服务实现类
 * </p>
 */
@Slf4j
@Service
public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkOrder> implements WorkOrderService {
    @Autowired
    WorkOrderItemService workOrderItemService;

    @Autowired
    StockService stockService;

    @Autowired
    StockLockService stockLockService;

    @Autowired
    OrderBarcodeService orderBarcodeService;

    @Autowired
    MatrUnitService matrUnitService;
    @Autowired
    MatrService matrService;

    @Autowired
    StockProcessService stockProcessService;

    @Autowired
    StockProcessItemService stockProcessItemService;


    @Autowired
    StockZeroService stockZeroService;

    @Resource
    TertiaryStockService tertiaryStockService;

//    @Override
//    public void post(String workOrderId) {
//        WorkOrder workOrder = this.getById(workOrderId);
//        if (workOrder == null) {
//            throw new BusinessException("错误的工单ID！");
//        }
//        this._checkWorkOrder(workOrder);
//        List<WorkOrderItem> workOrderItems = workOrderItemService.list(
//                new QueryWrapper<WorkOrderItem>().eq("work_order_id", workOrderId));
//
//        workOrderItems.stream().filter(s -> s.getPackId() != null && "1".equals(s.getMatrType())).forEach(workOrderItem -> {
//            if (workOrder.getDirection() > 0) {
//                workOrderItem.setMatrId("-1");
//                addPackageStock(workOrder, workOrderItem, "0");
//                workOrderItems.stream().filter(s -> workOrderItem.getId().equals(s.getPackItemId())).forEach(item -> {
//                    Stock stock = stockService.getOne(new QueryWrapper<Stock>().select("id").eq("line_id", workOrderItem.getId()));
//                    addPackageStock(workOrder, item, stock.getId());
//                });
//            } else {
//                minusStock(workOrder, workOrderItem);
//            }
//
//        });
//        workOrderItems.stream().filter(s -> StringUtils.isBlank(s.getPackId())).filter(s -> "0".equals(s.getMatrType()) && StringUtils.isBlank(s.getPackItemId())).forEach(workOrderItem -> {
//            if (workOrder.getDirection() > 0) {
//                addStock(workOrder, workOrderItem, "0");
//            } else {
//                minusStock(workOrder, workOrderItem);
//            }
//        });
//        /*for (WorkOrderItem workOrderItem : workOrderItems) {
//            if (workOrder.getDirection() > 0) {
//                addStock(workOrder, workOrderItem);
//            } else {
//                minusStock(workOrder, workOrderItem);
//            }
//        }*/
//        createBill(workOrder, workOrderItems);
////        CommonService.fsdStockHandle();
//        baseMapper.updateWorkOrder(workOrderId);
//
//        //更新该科室月度消耗量、消耗额
//        UtilBudget.updateBudget(workOrder.getDeptId());
//
//        //更新耗材库存仓库关系
//        workOrderItems.stream().collect(Collectors.groupingBy(workOrderItem -> workOrderItem.getMatrId())).keySet().forEach(matrId -> {
//            CommonService.updateMatrStockNums(matrId, workOrder.getWarehouseId());
//        });
//    }

    @Override
    public void postBatch(List<String> workOrderIds) {
        List<WorkOrder> workOrderList = this.list(new QueryWrapper<WorkOrder>().in("id", workOrderIds));
        WorkOrder workOrder = workOrderList.get(0);
        if (workOrderList == null) {
            throw new BusinessException("错误的工单ID！");
        }
        //       单据校验
        workOrderList.forEach(this::_checkWorkOrder);

        List<WorkOrderItem> workOrderItems = workOrderItemService.list(
                new QueryWrapper<WorkOrderItem>().in("work_order_id", workOrderIds));
        Map<String, List<WorkOrderItem>> idItemMap = workOrderItems.stream().collect(
                Collectors.groupingBy(WorkOrderItem::getWorkOrderId));
        Map<String, List<WorkOrder>> idWorkMap = workOrderList.stream().collect(
                Collectors.groupingBy(WorkOrder::getId));
        long starTime = System.currentTimeMillis();
        //      跟台包
        workOrderItems.stream().filter(s -> s.getPackId() != null && "1".equals(s.getMatrType())).forEach(workOrderItem -> {
            WorkOrder workOrderPack = idWorkMap.get(workOrderItem.getWorkOrderId()).get(0);
            if (workOrder.getDirection() > 0) {
                workOrderItem.setMatrId("-1");
                addPackageStock(workOrderPack, workOrderItem, "0");
                workOrderItems.stream().filter(s -> workOrderItem.getId().equals(s.getPackItemId())).forEach(item -> {
                    Stock stock = stockService.getOne(new QueryWrapper<Stock>().select("id").eq("line_id", workOrderItem.getId()));
                    addPackageStock(workOrderPack, item, stock.getId());
                });
            } else {
                minusStock(workOrderPack, workOrderItem);
            }

        });
        // 普通耗材
        if (!workOrder.getBusType().equals(WorkOrderType.IN_PACKAGE)) {
            if (workOrder.getDirection() > 0) {
                addStockBatch(workOrderList, workOrderItems, "0", idWorkMap);
            } else {
                if (PurchaseType.REAGENT.getKey().equals(workOrder.getPurchaseOrderType()) && StringUtils.isNotEmpty(workOrder.getReagentTeamId())) {
                    // 试剂类型，配送到试剂组，复制库存到三级库
                    tertiaryStockService.addStock(workOrder, workOrderItems);
                }

                // 数量化管理的耗材id
                List<String> matrIdListMagnum = matrService.listByIds(workOrderItems.stream().map(WorkOrderItem::getMatrId).collect(Collectors.toList()))
                        .stream().filter(item -> item.getFlagMagnum() != null && item.getFlagMagnum()).map(Matr::getId).collect(Collectors.toList());


                List<WorkOrderItem> workOrderItemsNum = workOrderItems.stream().filter(tmp  ->  matrIdListMagnum.contains(tmp.getMatrId())).collect(Collectors.toList());
                List<WorkOrderItem> workOrderItemsNotNum = workOrderItems.stream().filter(tmp  ->  !matrIdListMagnum.contains(tmp.getMatrId())).collect(Collectors.toList());

                if (workOrderItemsNum.size() > 0) {
                    minusStockBatchMatrNum(workOrderItemsNum);
                }
                if (workOrderItemsNotNum.size() > 0) {
                    minusStockBatch(workOrderItemsNotNum);
                }

            }
        }
        for (String workOrderId : idItemMap.keySet()) {
            List<WorkOrderItem> items = idItemMap.get(workOrderId);
            List<WorkOrder> workOrders = idWorkMap.get(workOrderId);
//            createBill(workOrders.get(0), items);
            }
//        CommonService.fsdStockHandle();

        long endTime = System.currentTimeMillis(); //获取结束时间
        String ms = DateUtils.formatTime(endTime - starTime);
        log.info(workOrder.getBusType()+"出入库过账执行时间" + ms);
        //更新该科室月度消耗量、消耗额
        workOrderList.forEach(workOrder1 -> {
            //         更新临采属性
        baseMapper.updateWorkOrder(workOrder1.getId());
        UtilBudget.updateBudget(workOrder1.getDeptId());
        });
        //  更新耗材库存仓库关系
        CommonService.updateMatrStockNums(workOrderList);

    }

    @Override
    public void post(String inWorkOrderId, String outWorkOrderId,Boolean isUpdateStockQty) {
        WorkOrder inWorkOrder = this.getById(inWorkOrderId);
        if (inWorkOrder == null) {
            throw new BusinessException("错误的入库工单ID！");
        }
        this._checkWorkOrder(inWorkOrder);
        WorkOrder outWorkOrder = this.getById(outWorkOrderId);
        if (outWorkOrder == null) {
            throw new BusinessException("错误的出库工单ID！");
        }
        this._checkWorkOrder(outWorkOrder);
        List<WorkOrderItem> workOrderItems = workOrderItemService.list(
                new QueryWrapper<WorkOrderItem>().eq("work_order_id", inWorkOrderId));
        Collection<Stock> stockList = new ArrayList<>();
        String targetWarehouseId = inWorkOrder.getWarehouseId();
        String targetWarehouseName = inWorkOrder.getWarehouseName();

        // 数量化管理的耗材id
//        List<String> matrIdListMagnum = matrService.listByIds(workOrderItems.stream().map(WorkOrderItem::getMatrId).collect(Collectors.toList()))
//                .stream().filter(item -> item.getFlagMagnum() != null && item.getFlagMagnum()).map(Matr::getId).collect(Collectors.toList());

        for (WorkOrderItem workOrderItem : workOrderItems) {
            Stock stock = stockService.getById(workOrderItem.getStockId());
            stock.setWarehouseId(targetWarehouseId);
            stock.setWarehouseName(targetWarehouseName);
            stock.setLocationId(workOrderItem.getLocationId());
            stock.setLocationName(workOrderItem.getLocationName());

            if (isUpdateStockQty) {
                //科室消耗单冲红，单品数量可修改
                if ( outWorkOrder.getBusType().equals(WorkOrderType.IN_USE_RED)) {
                    stock.setSkuQty(workOrderItem.getSkuQty());
                    stock.setPackageQty(stock.getSkuQty());
                    stock.setAmount(workOrderItem.getAmount());
                }
                //科室退货入库
                if (outWorkOrder.getBusType().equals(WorkOrderType.IN_DEPT_RETURN)) {
                    stock.setSkuQty(stock.getSkuQty() + workOrderItem.getSkuQty());
                    stock.setPackageQty(stock.getSkuQty());
                    stock.setAmount(workOrderItem.getAmount());
                }
            }

            stockList.add(stock);
        }
        stockService.updateBatchById(stockList);
        baseMapper.updateWorkOrder(inWorkOrderId);
    }

    private void addStockBatch(List<WorkOrder> workOrderList, List<WorkOrderItem> workOrderItemList, String id,Map<String, List<WorkOrder>> workOrderMap) {
        List<String> workOrderIds = workOrderList.stream().map(WorkOrder::getId).collect(Collectors.toList());
        WorkOrder workOrderType = workOrderList.get(0);

        // 数量入库
        if (WorkOrderType.IN_NUMBER.equals(workOrderType.getBusType())) {
            _inNumber(workOrderList,workOrderItemList,workOrderMap);
            return;
        }

        // 数量出库
        if (WorkOrderType.OUT_NUMBER.equals(workOrderType.getBusType())) {
            _outNumber(workOrderList,workOrderItemList,workOrderMap);
            return;
        }
        List<OrderBarcode> barcodeList = orderBarcodeService.list(new QueryWrapper<OrderBarcode>()
                .in("work_order_id", workOrderIds));
        Map<String, WorkOrderItem> snItemMap = new HashMap<>();
        List<Stock> stocksSave = new ArrayList<>();

        // 数量化管理的耗材id
        List<String> matrIdListMagnum = matrService.listByIds(workOrderItemList.stream().map(WorkOrderItem::getMatrId).collect(Collectors.toList()))
                .stream().filter(item -> item.getFlagMagnum() != null && item.getFlagMagnum()).map(Matr::getId).collect(Collectors.toList());

        if (barcodeList == null || barcodeList.isEmpty()) {//没有进行过编码操作
            barcodeList = new ArrayList<>();
            //  SN不为空，是红冲入库
            if ( workOrderType.getBusType().equals(WorkOrderType.IN_DEPT_RETURN) || workOrderType.getBusType().equals(WorkOrderType.IN_USE_RED) || workOrderType.getBusType().equals(WorkOrderType.IN_OPRT_RED)) { //SN不为空，是红冲入库
                for (WorkOrderItem workOrderItem : workOrderItemList) {
                    OrderBarcode orderBarcode = new OrderBarcode(workOrderItem.getWorkOrderId(), workOrderItem.getId(), workOrderItem.getSn(),
                            workOrderItem.getRfid(),
                            workOrderItem.getUdi(),workOrderItem.getPackageQty());
                    barcodeList.add(orderBarcode);
                    snItemMap.put(orderBarcode.getSn(), workOrderItem);
                }
            } else {
                //按照入库明细包装数量数据汇总，生成条码 (有小数的明细 自动向上取整)
                // 非数量化管理的耗材
                double sumBarCodeCount = workOrderItemList.stream().filter(item -> !matrIdListMagnum.contains(item.getMatrId()))
                        .mapToDouble(item-> Math.ceil(item.getPackageQty())).sum();
                sumBarCodeCount += workOrderItemList.stream().filter(item -> matrIdListMagnum.contains(item.getMatrId()))
                        .count();

                int snCount = Integer.parseInt(UtilNum.getString(sumBarCodeCount));
                List<String> snList = serialRuleAdapter.getSerialRuleService().batchGenerateCode(SerialKeys.WM_STOCK_PROCESS_SN, snCount);
                int snNumber = 0;

                // 非数量化管理的明细
                List<WorkOrderItem> workOrderItemListMagnumFalse = workOrderItemList.stream().filter(item -> !matrIdListMagnum.contains(item.getMatrId())).collect(Collectors.toList());
                if (!workOrderItemListMagnumFalse.isEmpty()) {
                    for (WorkOrderItem workOrderItem : workOrderItemListMagnumFalse) {
//                    明细存在小数的向上取整
                        double ceilCount = Math.ceil(workOrderItem.getPackageQty());
                        int packageCount = Integer.parseInt(UtilNum.getString(ceilCount));
                        for (int i = 0; i < packageCount; i++) {
                            double packageQty = 1D;
                            if ((UtilNum.sub(workOrderItem.getPackageQty(), (double) i) < 1D)) {
                                packageQty = UtilNum.sub(workOrderItem.getPackageQty(), (double) i);
                            }
                            OrderBarcode orderBarcode = new OrderBarcode(workOrderItem.getWorkOrderId(), workOrderItem.getId(), workOrderItem.getSn(),
                                    workOrderItem.getRfid(),
                                    workOrderItem.getUdi(),packageQty);
                            orderBarcode.setSn(snList.get(snNumber));
                            barcodeList.add(orderBarcode);
                            snNumber++;
                            snItemMap.put(orderBarcode.getSn(), workOrderItem);
                        }
                    }
                }

                // 数量化管理的明细
                List<WorkOrderItem> workOrderItemListMagnumTrue = workOrderItemList.stream().filter(item -> matrIdListMagnum.contains(item.getMatrId())).collect(Collectors.toList());
                for (WorkOrderItem workOrderItem : workOrderItemListMagnumTrue) {
                    OrderBarcode orderBarcode = new OrderBarcode(workOrderItem.getWorkOrderId(), workOrderItem.getId(), workOrderItem.getSn(),
                            workOrderItem.getRfid(),
                            workOrderItem.getUdi(),workOrderItem.getPackageQty());
                    orderBarcode.setSn(snList.get(snNumber));
                    barcodeList.add(orderBarcode);
                    snNumber++;
                    snItemMap.put(orderBarcode.getSn(), workOrderItem);
                }

                if (!barcodeList.isEmpty()) {
                    orderBarcodeService.saveOrUpdateBatch(barcodeList);
                }
            }
        } else {
            // 手动更新编码的udi
            for (OrderBarcode orderBarcode : barcodeList) {
                WorkOrderItem orderItem = workOrderItemService.getById(orderBarcode.getWorkOrderItemId());
                if (orderItem != null) {
                    orderBarcode.setUdi(orderItem.getUdi());
                    snItemMap.put(orderBarcode.getSn(), orderItem);
                }
            }
            orderBarcodeService.saveOrUpdateBatch(barcodeList);
        }
        long forTime = System.currentTimeMillis();
        barcodeList.forEach(item -> {
            WorkOrderItem workOrderItem = snItemMap.get(item.getSn());
            WorkOrder workOrder = workOrderMap.get(item.getWorkOrderId()).get(0);
            Stock stock = null;
            if ( workOrderType.getBusType().equals(WorkOrderType.IN_DEPT_RETURN)
                    || workOrderType.getBusType().equals(WorkOrderType.IN_USE_RED)
                    || workOrderType.getBusType().equals(WorkOrderType.IN_OPRT_RED)) { //SN不为空，是红冲入库
                 stock = stockService.getById(workOrderItem.getStockId()); //如果是退库，直接在原有基础上修改数量和包装，否则创建新的数据
            }
        // TODO 需要查询0库存  科室退货入库，科室消耗 冲红入库，病人消耗模块、HIS退费或者病人消耗冲红
            if (stock == null && (workOrder.getBusType().equals(WorkOrderType.IN_DEPT_RETURN) || workOrder.getBusType().equals(WorkOrderType.IN_USE_RED) || workOrder.getBusType().equals(WorkOrderType.IN_OPRT_RED))) {
                //需要查询0库存  科室退货入库，科室消耗 冲红入库，病人消耗模块、HIS退费或者病人消耗冲红
                stock = new Stock();
                StockZero stockZero = stockZeroService.getById(workOrderItem.getStockId());
                if (stockZero != null) { BeanUtils.copyProperties(stockZero, stock); }
            }
            if (stock == null) {
                stock = new Stock();
                BeanUtils.copyProperties(workOrderItem, stock, "id");
                stock.setPackStockId(id)
                    .setSupplierId(workOrder.getSupplierId())
                    .setSupplierName(workOrder.getSupplierName())
                        .setWarehouseId(workOrder.getWarehouseId())
                        .setWarehouseName(workOrder.getWarehouseName())
                        .setFlagConsignment(workOrder.getFlagConsignment())
                        .setFlagOmoc(workOrder.getFlagOmoc())
                        .setPackageQty(1d);
                stock.setFlagUniqueCode(true);
                //一物一码的也有可能选择包装单位
                stock.setSkuQty(workOrderItem.getSkuQty() / workOrderItem.getPackageQty());
                stock.setSkuPrice(workOrderItem.getSkuPrice());
                stock.setAmount(stock.getSkuQty() * stock.getSkuPrice());
                //小数的
                if (item.getPackageQty() != null  && item.getPackageQty() < 1) {
                    List<MatrUnit> matrUnitList = matrUnitService.list(Wrappers.<MatrUnit>query().eq("matr_id",workOrderItem.getMatrId()).eq("unit",workOrderItem.getPackageUnit()));
                    if (matrUnitList == null || matrUnitList.size() < 1) throw new BusinessException("入库失败，未找到包装单位[%s]",workOrderItem.getPackageUnit()) ;
                    if (matrUnitList.size() > 1) throw new BusinessException("入库失败，未找到多个包装单位[%s]",workOrderItem.getPackageUnit());
                    stock.setSkuQty(matrUnitList.get(0).getRate()*item.getPackageQty());
                    stock.setAmount(matrUnitList.get(0).getPrice()*item.getPackageQty());
                    stock.setPackageQty(item.getPackageQty());
                }
                stock.setUdi(item.getUdi());
                stock.setFlagTemporaryPurchase(workOrderItem.getFlagTemporaryPurchase());


                stock.setSn(item.getSn());
                stock.setInTime(new Date());
                // 数量化管理
                if (matrIdListMagnum.contains(stock.getMatrId())) {
                    stock.setSkuQty(workOrderItem.getSkuQty());
                    stock.setPackageUnit(workOrderItem.getSkuUnit());
                    stock.setPackageQty(stock.getSkuQty());
                    stock.setAmount(stock.getSkuPrice() * stock.getSkuQty());
                }
            } else {
                // 数量化管理
                if (matrIdListMagnum.contains(stock.getMatrId())) {
                    stock.setSkuQty(stock.getSkuQty() + workOrderItem.getSkuQty());
                    stock.setPackageUnit(workOrderItem.getSkuUnit());
                    stock.setPackageQty(stock.getSkuQty());
                    stock.setAmount(stock.getSkuPrice() * stock.getSkuQty());
                } else{
                    stock.setPackageUnit(workOrderItem.getPackageUnit())
                            .setPackageQty(workOrderItem.getPackageQty())
                            .setSkuUnit(workOrderItem.getSkuUnit())
                            .setSkuQty(workOrderItem.getSkuQty())
                            .setSkuPrice(workOrderItem.getSkuPrice())
                            .setAmount(workOrderItem.getAmount());
                }
                stock
                    .setWarehouseId(workOrder.getWarehouseId())
                    .setWarehouseName(workOrder.getWarehouseName());
            }



            stocksSave.add(stock);

            // stockService.saveOrUpdate(stock);

            if (
                    workOrder.getBusType().equals(WorkOrderType.IN_DEPT_RETURN)
                            || workOrder.getBusType().equals(WorkOrderType.IN_USE_RED)
                            || workOrder.getBusType().equals(WorkOrderType.IN_OPRT_RED)
            ) { //需要删除0库存  科室退货入库，科室消耗 冲红入库，病人消耗模块、HIS退费或者病人消耗冲红
                stockZeroService.remove(new QueryWrapper<StockZero>().eq("sn", item.getSn()));
            }
        });
        String foreach = DateUtils.formatTime(System.currentTimeMillis() - forTime);
        log.info("生成foreach执行时间"+"==" + foreach);
        if (!stocksSave.isEmpty()) {
            stockService.saveOrUpdateBatch(stocksSave);
        }
    }

    // 数量入库
    private void _inNumber(List<WorkOrder> workOrderList, List<WorkOrderItem> workOrderItemList,Map<String, List<WorkOrder>> workOrderMap) {
        List<Stock> stocksSave = new ArrayList<>();
        List<OrderBarcode> barcodeList = new ArrayList<>();
        List<String> snList = serialRuleAdapter.getSerialRuleService().batchGenerateCode(SerialKeys.WM_STOCK_PROCESS_SN, workOrderItemList.size());
        AtomicInteger snIndex = new AtomicInteger();
        workOrderItemList.forEach(workOrderItem -> {
            WorkOrder workOrder = workOrderMap.get(workOrderItem.getWorkOrderId()).get(0);
            Stock stock = new Stock();
            BeanUtils.copyProperties(workOrderItem, stock, "id");
            stock.setSupplierId(workOrder.getSupplierId())
                    .setSupplierName(workOrder.getSupplierName())
                    .setWarehouseId(workOrder.getWarehouseId())
                    .setWarehouseName(workOrder.getWarehouseName())
                    .setFlagConsignment(workOrder.getFlagConsignment())
                    .setFlagOmoc(workOrder.getFlagOmoc())
                    ;
            stock.setFlagUniqueCode(true);
            stock.setFlagTemporaryPurchase(workOrderItem.getFlagTemporaryPurchase());
            stock.setSn(snList.get(snIndex.get()));
            stock.setInTime(new Date());
            stocksSave.add(stock);
            snIndex.getAndIncrement();

            OrderBarcode orderBarcode = new OrderBarcode(workOrderItem.getWorkOrderId(), workOrderItem.getId(), workOrderItem.getSn(),
                    workOrderItem.getRfid(),
                    workOrderItem.getUdi(),workOrderItem.getPackageQty());
            orderBarcode.setSn(stock.getSn()).setWorkOrderId(workOrderItem.getWorkOrderId()).setWorkOrderItemId(workOrderItem.getId());
            barcodeList.add(orderBarcode);
        });
        stockService.saveOrUpdateBatch(stocksSave);
        orderBarcodeService.saveOrUpdateBatch(barcodeList);
    }

    // 数量出库
    private void _outNumber(List<WorkOrder> workOrderList, List<WorkOrderItem> workOrderItemList,Map<String, List<WorkOrder>> workOrderMap) {

    }
    private void minusStockBatch(List<WorkOrderItem> workOrderItems) {
        List<String> stockIds = workOrderItems.stream().map(WorkOrderItem::getStockId).collect(Collectors.toList());
        List<String> snList = workOrderItems.stream().map(WorkOrderItem::getSn).collect(Collectors.toList());
        stockLockService.unlockBatch(snList);
        _minusStockBatch(stockIds);
    }


    //数量化管理 扣减库存
    private void minusStockBatchMatrNum(List<WorkOrderItem> workOrderItems) {
//        List<String> snList = workOrderItems.stream().map(WorkOrderItem::getSn).collect(Collectors.toList());
//        //批量解除实物锁
//        stockLockService.unlockBatchWithBusKeyValue(snList,transfer.getId());
//
//        //扣减库存
//        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("sn", snList));
//        Map<String,TransferItem> transferItemMapBySn = transferItemList.stream().collect(Collectors.toMap(TransferItem::getSn, t -> t));
//        stockList.forEach(stock -> {
//            double skuQtyNew = stock.getSkuQty() - transferItemMapBySn.get(stock.getSn()).getSkuQty();
//            if (skuQtyNew  < 0) {
//                throw  new BusinessException("库存不足");
//            }
//            stock.setSkuQty(skuQtyNew);
//            stock.setPackageQty(stock.getSkuQty());
//            stock.setAmount(stock.getSkuPrice() * stock.getSkuQty());
//            stock.setWarehouseId(transfer.getFromWarehouseId());
//            stock.setWarehouseName(transfer.getFromWarehouseName());
//            stock.setLocationId(transfer.getFromLocationId());
//            stock.setLocationName(transfer.getFromLocationName());
//        });
//        stockService.updateBatchById(stockList);

        //更新数量锁
//        stockLockService.updateLockQty(entity.getStockId(),entity.getTransferId(),entity.getSkuQty());
    }

    private void minusStock(WorkOrder workOrder, WorkOrderItem workOrderItem) {
        String warehouseId = workOrder.getWarehouseId();
        if (Long.parseLong(workOrderItem.getStockId()) > 0) {
            _minusStock(workOrderItem.getStockId());
            stockLockService.unlock(workOrderItem.getStockId());
        } else if (StringUtils.isNotBlank(workOrderItem.getSn())) {
            _minusStock(warehouseId, workOrderItem.getSn(), UniqueCodeType.SN);
            stockLockService.unlock(workOrderItem.getSn(), UniqueCodeType.SN, workOrder.getWarehouseId());
        } else if (StringUtils.isNotBlank(workOrderItem.getRfid())) {
            _minusStock(warehouseId, workOrderItem.getSn(), UniqueCodeType.RFID);
            stockLockService.unlock(workOrderItem.getSn(), UniqueCodeType.RFID, workOrder.getWarehouseId());
        } else if (StringUtils.isNotBlank(workOrderItem.getUdi())) {
            _minusStock(warehouseId, workOrderItem.getSn(), UniqueCodeType.UDI);
            stockLockService.unlock(workOrderItem.getUdi(), UniqueCodeType.UDI, workOrder.getWarehouseId());
        } else {
            throw new BusinessException("出库时必须提供StockID或者唯一码");
        }
    }

    private void _minusStock(String warehouseId, String uc, UniqueCodeType ucType) {
        QueryWrapper<Stock> wrapper = new QueryWrapper<Stock>();
        wrapper.eq("warehouse_id", warehouseId)
                .eq(ucType.toString().toLowerCase(), uc);
        Stock stock = stockService.getOne(wrapper);
        if (stock == null) {
            throw new BusinessException("未能按照提供的UC码检索到库存记录，uc：" + uc);
        }
        _resetStock(stock);
    }

    private void _minusStock(String stockId) {
        Stock stock = stockService.getById(stockId);
        if (stock == null) {
            throw new BusinessException("未能按照提供的StockId检索到库存记录，stockId：" + stockId);
        }
        _resetStock(stock);
    }

    private void _minusStockBatch(List<String> stockIds) {
        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIds));
        if (stockList == null) {
            throw new BusinessException("未能按照提供的StockId检索到库存记录");
        }
        if (stockList.size() != stockIds.size()) {
            throw new BusinessException("按照提供的StockId检索到库存记录不相同,请检查");
        }
        _resetStockBatch(stockList);
    }

    private void _resetStock(Stock stock) {
        stock.setPackageQty(0.0);
        stock.setSkuQty(0.0);
        stock.setAmount(0.0);
        stock.setMdate(new Date());
        stockService.removeById(stock);

        StockZero stockZero = new StockZero();
        BeanUtils.copyProperties(stock,stockZero);
        stockZeroService.save(stockZero);
    }

    private void _resetStockBatch(List<Stock> stocks) {
        List<Stock> stockUpdate = new ArrayList<>(stocks.size());
        stocks.forEach(stock -> {
            stock.setPackageQty(0.0);
            stock.setSkuQty(0.0);
            stock.setAmount(0.0);
            stock.setMdate(new Date());
            stockUpdate.add(stock);
        });

        List<StockZero> StockZeroSaveList = new ArrayList<StockZero>(stocks.size());
        stockService.removeByIds(stockUpdate.stream().map(Stock::getId).collect(Collectors.toList()));
        com.scs.application.core.utils.BeanUtils.copyProperties(stockUpdate,StockZeroSaveList, StockZero.class);
        stockZeroService.saveBatch(StockZeroSaveList);
    }

    @Override
    public void resetStockBatch(List<Stock> stocks) {
        this._resetStockBatch(stocks);
    }

    @Deprecated
    private void createBill(WorkOrder workOrder, List<WorkOrderItem> workOrderItems) {
        if (true) throw  new  RuntimeException("_createCommonBill方法已过期");
        /*暂时注释掉，待后期改造wyt20211208 if (WorkOrderType.WorkOrderTypeBillInAll.contains(workOrder.getBusType().toUpperCase())
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.OUT_SP)) {
            // 购销的供应商入库单,退货出库单创建记账单，金额按照工单的direction来确定
            // 代销的话，与记账单无关
            if (!workOrder.getFlagConsignment()) {
                Bill bill = _createCommonBill(workOrder);
                bill.setFlagDept(false);
                bill.setFlagSupplier(true);
                bill.setFlowStatus(GlobalConsts.FLOW_END_VALUE); //记帐单直接已审核
                billService.save(bill);
                billItemService.saveBatch(_createCommonBillItem(workOrder, bill.getId(), workOrderItems, workOrder.getDirection()));
                log.info("工单{} - {} 已记帐，记帐金额：{}元", workOrder.getBusKey(), workOrder.getSupplierName(), bill.getAmount());
            }
        } else if (workOrder.getBusType().equalsIgnoreCase(WorkOrderType.OUT_USE)
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.OUT_DIST)
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.OPRT_USE)
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.IN_USE_RED)  //科室冲红入库
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.IN_OPRT_RED)  //病人消耗冲红入库
                || workOrder.getBusType().equalsIgnoreCase(WorkOrderType.IN_DEPT_RETURN)) {  // 科室退库
            // 消耗出库和科室退货入库都创建记账单，因为肯定要计入科室成本；是否跟供应商有关，取决于代销标记
            Bill bill = _createCommonBill(workOrder);
            bill.setFlagDept(true);
            bill.setFlagSupplier(workOrder.getFlagConsignment());
            bill.setAmount(-bill.getAmount());  //出库记正值，入库记负值
            bill.setFlowStatus(GlobalConsts.FLOW_END_VALUE); //记帐单直接已审核
            billService.save(bill);
            billItemService.saveBatch(_createCommonBillItem(workOrder, bill.getId(), workOrderItems, -workOrder.getDirection()));
            log.info("工单{} - {} 已记帐，记帐金额：{}元", workOrder.getBusKey(), workOrder.getSupplierName(), bill.getAmount());
        }*/
        }

    /**
     * 创建通用的记账单
     *
     * @param workOrder
     * @return
     */
    @Deprecated
    private Bill _createCommonBill(WorkOrder workOrder) {
        if (true) throw  new  RuntimeException("_createCommonBill方法已过期");

        Bill bill = new Bill();
        bill.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.FINANCE_BILL_KEY));
        bill.setBusDate(workOrder.getBusDate());
        bill.setBusUser(workOrder.getBusUser());
        bill.setAmount(workOrder.getAmount() * workOrder.getDirection());
        bill.setSupplierId(workOrder.getSupplierId());
        bill.setSupplierName(workOrder.getSupplierName());
        bill.setDeptId(workOrder.getDeptId());
        bill.setDeptName(workOrder.getDeptName());
        bill.setFlagConsignment(workOrder.getFlagConsignment());
        bill.setFlagOmoc(workOrder.getFlagOmoc());

        //流程修改人、流程修改时间
        bill.setFlowModifier(workOrder.getFlowModifier());
        bill.setFlowModified(workOrder.getFlowModified());
        String refBusTable;
        switch (workOrder.getBusType()) {
            case WorkOrderType.IN_DEPT_RETURN: //科室退货入库
                refBusTable = "dept_return";
                break;
            case WorkOrderType.OUT_USE: //科室消耗单
                refBusTable = "dept_use";
                break;
            case WorkOrderType.IN_USE_RED: //科室消耗 冲红入库
                refBusTable = "dept_use";
                break;
            case WorkOrderType.OPRT_USE: //病人消耗模块、HIS接口消耗
                refBusTable = "dept_oprt_use";
                break;
            case WorkOrderType.IN_OPRT_RED: //病人消耗模块、HIS退费或者病人消耗冲红
                refBusTable = "dept_oprt_use";
                break;
            default:
                throw new BusinessException("生成记账单失败，busType类型错误，请联系开发人员");
        }

        return bill;
    }

    /**
     * 创建通用的记账单明细表
     *
     * @param workOrderItems
     * @return
     */
    @Deprecated
    private List<BillItem> _createCommonBillItem(WorkOrder workOrder, String billId, List<WorkOrderItem> workOrderItems, Integer direction) {
        if (true) throw  new  RuntimeException("_createCommonBillItem");
        List<BillItem> billItems = new ArrayList<>();
        for (WorkOrderItem workOrderItem : workOrderItems) {
            BillItem billItem = new BillItem();
            BeanUtils.copyProperties(workOrderItem, billItem);
            billItem.setId(null);
            billItem.setBillId(billId);
            billItem.setSkuQty(workOrderItem.getSkuQty() * direction);
            billItem.setAmount(workOrderItem.getAmount() * direction);
            billItem.setManufactureName(workOrderItem.getMfgName());
            billItem.setCertificateNo(workOrderItem.getCertificateNo());
            billItem.setRefBusTable(workOrder.getRefTable()).setRefBusId(workOrder.getRefId()).setRefBusKey(workOrder.getRefKey()).setRefBusType(workOrder.getBusType()).setRefBusItemId(workOrderItem.getRefBusItemId()).setReagentTeamId(workOrder.getReagentTeamId());
            billItems.add(billItem);
        }

        return billItems;
    }

    @Override
    public void calculateOrderPrice(String workOrderId) {
        List<WorkOrderItem> workOrderItemList = workOrderItemService.list(new QueryWrapper<WorkOrderItem>().eq("work_order_id", workOrderId));
        double amount = 0d;
        boolean notEmpty = CollectionUtils.isNotEmpty(workOrderItemList);
        if (notEmpty) {
            amount = workOrderItemList.stream().mapToDouble(WorkOrderItem::getAmount).sum();
        }
        WorkOrder workOrder = super.getById(workOrderId);
        WorkOrder workOrder1 = new WorkOrder();
        BeanUtils.copyProperties(workOrder, workOrder1);
        workOrder1.setAmount(amount);
        // 入库明细全部删除时，重置耗材类型
        if (!notEmpty){
//            workOrder1.setPurchaseOrderType("");
        }
        super.saveOrUpdate(workOrder1);
    }

    @Override
    public TraceBackDTO getListBySN(String sn) {
        List<TraceBackOrderDTO> list = new ArrayList<>();
        TraceBackDTO traceBackDTO = new TraceBackDTO();
        Stock s = new Stock();
        //如果是RFID 或者UDI，去stok表找到对应的SN
        s = stockService.getStockByUniqueCode(sn);
        if (s == null) {
            return null;
        }
        sn = s.getSn();

        StockDTO stockDTO = new StockDTO();
        StockLock stockLock = stockLockService.getOne(Wrappers.<StockLock>query()
                .eq("stock_id", s.getId()));
        BeanUtils.copyProperties(s, stockDTO);
        if (stockLock != null) {
            stockDTO.setLockComment(stockLock.getLockComment());
            stockDTO.setLockQty(stockLock.getQty());
            stockDTO.setBusId(stockLock.getBusKeyValue());
            stockDTO.setBusType(stockLock.getBusType());
        }
        traceBackDTO.setStockDTO(stockDTO);

        String inWarehouseName = null;
//        sn 是否存在加工单中
        List<StockProcess> stockProcessList = new ArrayList<>();

        List<StockProcessItem> stockProcessItems = stockProcessItemService.list(Wrappers.<StockProcessItem>query()
                .select("process_id").eq("sn", sn));
        if (stockProcessItems.size() > 0) {
            List<String> idList = stockProcessItems.stream().map(StockProcessItem::getProcessId).collect(Collectors.toList());
            stockProcessList = stockProcessService
                    .list(Wrappers.<StockProcess>query().in("id", idList).eq("submit_status", 1));
            stockProcessList.forEach(stockProcess->{
                stockProcess.setBusId(stockProcess.getId());
                stockProcess.setBusType("PROCESS");
                stockProcess.setMenuRoute("processhistory");
                stockProcess.setOpenBusId(stockProcess.getId());
            });
        }

        StockProcess stockProcess = stockProcessService
                .getOne(Wrappers.<StockProcess>query().eq("sn", sn).eq("submit_status", 1));
        if (stockProcess != null) {
            stockProcess.setBusId(stockProcess.getId());
            stockProcess.setBusType("PROCESS");
            stockProcess.setMenuRoute("processhistory");
            stockProcess.setOpenBusId(stockProcess.getId());
            stockProcessList.add(stockProcess);
        }
        traceBackDTO.setProcessListrocesses(stockProcessList);
        //通过sn去workorderItem里找
        List<WorkOrderItemDTO> workOrderItems = workOrderItemService.workOrderItemBySN(sn);
        //通过sn去wm_order_barcode里找
        List<WorkOrderItemDTO> orderBarcodes = workOrderItemService.orderBarcodeBySN(sn);

        String menuRoute ="", openBusId ="";
        if (workOrderItems.size() > 0) {
            /*for (WorkOrderItemDTO dto : workOrderItems) {
                //调拨入库
                if (dto.getBusType().equals("IN_SHIFT")) {
                    inWarehouseName = dto.getWarehouseName();
                    continue;
                }
            }*/
            //根据refKey进行去重
            List<WorkOrderItemDTO> newWorkOrderItems = Lists.newArrayListWithCapacity(workOrderItems.size());
            for (WorkOrderItemDTO dto : workOrderItems) {
                if (StringUtils.isNotBlank(dto.getRefKey())) {
                    if (!newWorkOrderItems.stream().filter(item -> dto.getRefKey().equals(item.getRefKey())).findFirst().isPresent()) {
                        List<WorkOrderItemDTO> items = workOrderItems.stream().filter(item -> dto.getRefKey().equals(item.getRefKey())).collect(Collectors.toList());
                        if (items.size() > 1) {
                            WorkOrderItemDTO workOrderItemDTO = items.get(0);
                            items.stream().forEach(item -> {
                                if (item.getBusKey().toLowerCase().indexOf("in") > -1) { //调入仓库
                                    workOrderItemDTO.setInWarehouseName(item.getWarehouseName());
                                } else if (item.getBusKey().toLowerCase().indexOf("out") > -1) { //调出仓库
                                    workOrderItemDTO.setWarehouseName(item.getWarehouseName());
                                }
                            });
                            newWorkOrderItems.add(workOrderItemDTO);
                        } else {
                            newWorkOrderItems.addAll(items);
                        }
                    }
                } else {
                    newWorkOrderItems.add(dto);
                }
            }
            workOrderItems = newWorkOrderItems;
            for (WorkOrderItemDTO dto : workOrderItems) {
                TraceBackOrderDTO traceBackOrderDTO = new TraceBackOrderDTO();
                BeanUtils.copyProperties(dto,traceBackOrderDTO);

                menuRoute ="";
                openBusId ="";
                if (StringUtils.isNotBlank(dto.getBusType())) {
                    menuRoute ="";
                    switch (dto.getBusType()) {
                        // 手动入库
                        case WorkOrderType.IN_MANUAL: {
                            menuRoute ="inorderManual";
                            break;
                        }
                        // 采购入库
                        case WorkOrderType.IN_ASN: {
                            menuRoute ="inorderSP";
                            break;
                        }
                        // 跟台包入库
                        case WorkOrderType.IN_PACKAGE: {
                            menuRoute ="inorderPackage";
                            break;
                        }
                        // 期初入库
                        case WorkOrderType.IN_INIT: {
                            menuRoute ="inorderInit";
                            break;
                        }
                        // 科室退货入库
                        case WorkOrderType.IN_DEPT_RETURN: {
                            menuRoute ="deptreturn";
                            openBusId =dto.getRefId();
                            break;
                        }
                        // 供应商退货出库
                        case WorkOrderType.OUT_SP: {
                            menuRoute ="spreturn";
                            break;
                        }
                        // 科室消耗 冲红入库
                        case WorkOrderType.IN_USE_RED: {
                            menuRoute ="deptuse";
                            openBusId =dto.getRefId();
                            break;
                        }

                        // 科室消耗单
                        case WorkOrderType.OUT_USE: {
                            menuRoute ="deptuse";
                            openBusId =dto.getRefId();
                            break;
                        }
                        // 病人消耗 出库
                        case WorkOrderType.OPRT_USE: {
                            menuRoute ="oprtuse";
                            openBusId =dto.getRefId();
                            break;
                        }
                        // 病人消耗 冲红入库
                        case WorkOrderType.IN_OPRT_RED: {
                            menuRoute ="oprtuse";
                            openBusId =dto.getRefId();
                            break;
                        }
                        // 默认调拨
                        default: {
                            // 调拨入库
                            if (dto.getBusType().indexOf("IN_SHIFT") != -1) {
                                menuRoute ="transfer";
                                openBusId =dto.getRefId();
                            } else if (dto.getBusType().indexOf("OUT_SHIFT") != -1) { // 调拨出库
                                menuRoute ="transfer";
                                openBusId =dto.getRefId();
                            }
                            break;
                        }
                    }
                }
                if (StringUtils.isNotBlank(dto.getRefKey())) {
                    traceBackOrderDTO.setBusKey(dto.getRefKey());
                }
                if (StringUtils.isNotBlank(dto.getRefId())) {
                    traceBackOrderDTO.setBusId(dto.getRefId());
                }

                traceBackOrderDTO.setMenuRoute(menuRoute);
                if (StringUtils.isBlank(openBusId)) {
                    openBusId = dto.getWorkOrderId();
                }
                traceBackOrderDTO.setOpenBusId(openBusId);

                //调拨出库
                if (dto.getBusType().equals(WorkOrderType.OUT_SHIFT)) {
                    List<WorkOrder> workOrders = this.baseMapper.workOrderBySN(dto.getRefKey(), WorkOrderType.IN_SHIFT, sn);
                    if (workOrders.size() == 1) {
                        dto.setInWarehouseName(workOrders.get(0).getWarehouseName());
                        traceBackOrderDTO.setInWarehouseName(workOrders.get(0).getWarehouseName());
                        traceBackOrderDTO.setBusKey(workOrders.get(0).getRefKey());
                        traceBackOrderDTO.setBusId(workOrders.get(0).getRefId());
                    } else if (workOrders.size() > 1) {
                        throw new BusinessException("同一个调拨单号出现多条调拨入库单");
                    }
                } else if (dto.getBusType().equals(WorkOrderType.IN_SHIFT)) {
                    continue;
                }
                list.add(traceBackOrderDTO);
            }
        }
        if (orderBarcodes.size() > 0) {
            orderBarcodes.forEach(o -> {
                TraceBackOrderDTO traceBackOrderDTO = new TraceBackOrderDTO();
                traceBackOrderDTO.setBusId(o.getWorkOrderId());
                BeanUtils.copyProperties(o,traceBackOrderDTO);
                switch (o.getBusType()) {
                    // 手动入库
                    case WorkOrderType.IN_MANUAL: {
                        traceBackOrderDTO.setMenuRoute("inorderManual");
                        break;
                    }
                    // 采购入库
                    case WorkOrderType.IN_ASN: {
                        traceBackOrderDTO.setMenuRoute("inorderSP");
                        break;
                    }
                    // 跟台包入库
                    case WorkOrderType.IN_PACKAGE: {
                        traceBackOrderDTO.setMenuRoute("inorderPackage");
                        break;
                    }
                    // 期初入库
                    case WorkOrderType.IN_INIT: {
                        traceBackOrderDTO.setMenuRoute("inorderInit");
                        break;
                    }
                }
                traceBackOrderDTO.setOpenBusId(o.getWorkOrderId());
                list.add(traceBackOrderDTO);
            });
        }
        traceBackDTO.setList(list);
        return traceBackDTO;
    }

    private void addPackageStock(WorkOrder workOrder, WorkOrderItem workOrderItem, String id) {

        this._checkWorkOrder(workOrder);
        //按照入库明细数据，添加sn记录
        double packageQty = workOrderItem.getPackageQty();
        if (packageQty != Double.valueOf(packageQty).intValue()) {
            throw new BusinessException("SN生成校验失败，入库包装数量必须为整数！");
        }

        OrderBarcode orderBarcode = new OrderBarcode(workOrder.getId(), workOrderItem.getId(), workOrderItem.getSn(),
                workOrderItem.getRfid(),
                workOrderItem.getUdi(),1d);
        orderBarcode.setSn(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.WM_STOCK_PROCESS_SN)).setUdi(workOrderItem.getUdi());
        orderBarcodeService.save(orderBarcode);

        Stock stock = new Stock();
        BeanUtils.copyProperties(workOrderItem, stock);
        stock.setPackStockId(id)
                .setSupplierId(workOrder.getSupplierId())
                .setSupplierName(workOrder.getSupplierName())
                .setWarehouseId(workOrder.getWarehouseId())
                .setWarehouseName(workOrder.getWarehouseName())
                .setFlagConsignment(workOrder.getFlagConsignment())
                .setFlagOmoc(workOrder.getFlagOmoc())
                .setInTime(new Date())
                .setSkuQty(workOrderItem.getSkuQty())
                .setSkuPrice(workOrderItem.getSkuPrice())
                .setAmount(stock.getSkuQty() * stock.getSkuPrice())
                .setSn(orderBarcode.getSn())
                .setUdi(orderBarcode.getUdi())
                .setId(null);
        if (Double.doubleToLongBits(workOrderItem.getPackageQty()) == Double.doubleToLongBits(1)) {
            stock.setFlagUniqueCode(true);
        }
        stockService.saveOrUpdate(stock);
    }

    /**
     * 检查工作记录表
     * 主表状态为end，检查是否有流程修改人和修改时间
     * 主子表金额是否一致
     * 子表包装 转换是否一致
     * 对应耗材包装属性是否正确
     * 供应商id和供应商名字是否存在
     * 科室id和科室name要么都空，要么都不空
     */
    private void _checkWorkOrder(WorkOrder workOrder) {
        if (StringUtils.isBlank(workOrder.getBusType())) {
            throw new BusinessException("出入库表校验失败！<br>工作记录表busType为空");
        }
        if (!WorkOrderType.WorkOrderTypeAll.contains(workOrder.getBusType())) {
            throw new BusinessException("出入库表校验失败！<br>工作记录表busType不在WorkOrderType.WorkOrderTypeAll列表中");
        }
        //流程修改人、流程修改时间
        if (GlobalConsts.FLOW_END_VALUE.equals(workOrder.getFlowStatus())) {
            if (StringUtils.isBlank(workOrder.getFlowModifier())) {
                throw new BusinessException("出入库表校验失败！<br>工作记录表流程最后修改人为空");
        }
            if (workOrder.getFlowModified() == null) {
                throw new BusinessException("出入库表校验失败！<br>工作记录表流程最后修改时间为空");
            }
        }

        if (StringUtils.isBlank(workOrder.getSupplierId())) {
            throw new BusinessException("出入库表校验失败！<br>主表供应商id为空");
        }
        if (StringUtils.isBlank(workOrder.getSupplierName())) {
            throw new BusinessException("出入库表校验失败！<br>主表供应商名称为空");
        }
        if (StringUtils.isNotBlank(workOrder.getDeptId()) && StringUtils.isBlank(workOrder.getDeptName())) {
            throw new BusinessException("出入库表校验失败！<br>主表有科室id，但是没有科室名称");
        }
        if (StringUtils.isBlank(workOrder.getDeptId()) && StringUtils.isNotBlank(workOrder.getDeptName())) {
            throw new BusinessException("出入库表校验失败！<br>主表有科室名称，但是没有科室id");
        }
        //非业务科室判断
        if (StringUtils.isNotBlank(workOrder.getDeptId())) {
            Dept dept = (Dept) CacheUtils.get(CacheUtils.BASE_DEPT, workOrder.getDeptId());
            if (dept != null && dept.getFlagBus() != true) {
                throw new BusinessException("出入库表校验失败！<br>科室【%s】非业务科室，不可以进行业务操作", dept.getName());
            }
        }


        //出入库表校验，此处不区分出入库，按绝对值进行判断
        //主表金额是否等于明细表金额
        List<WorkOrderItem> WorkOrderItems = workOrderItemService.list(Wrappers.<WorkOrderItem>query().eq("work_order_id", workOrder.getId()));

        //999、不同业务类型的业务数据校验
        double skuQtySum = WorkOrderItems != null ? WorkOrderItems.stream().mapToDouble(WorkOrderItem::getSkuQty).sum() : 0;
        double skuQtyBusSum = -1;
        String sumSql = null;
        String flagConsignment = workOrder.getFlagConsignment() ? "1" : "0";
        String flagOmoc = workOrder.getFlagOmoc() ? "1" : "0";
        switch (workOrder.getBusType()) {
            case WorkOrderType.IN_DEPT_RETURN: //科室退货入库
                sumSql = " select ifnull(sum(t1.sku_qty),0) as qtysum from wm_transfer_item t1 " +
                        "where  transfer_id = '" + workOrder.getRefId() + "' and supplier_id='" + workOrder.getSupplierId() + "' and flag_consignment='" + flagConsignment + "' and flag_omoc='" + flagOmoc + "' ";
                break;
            case WorkOrderType.OUT_USE: //科室消耗单
                sumSql = " select ifnull(sum(t1.sku_qty),0) as qtysum from dept_use_dtl t1   " +
                        "where  use_id = '" + workOrder.getRefId() + "' and supplier_id='" + workOrder.getSupplierId() + "' and flag_consignment='" + flagConsignment + "' and  flag_omoc='" + flagOmoc + "' ";
                break;
            case WorkOrderType.IN_USE_RED: //科室消耗 冲红入库
                sumSql = " select ifnull(sum(t1.sku_qty),0) as qtysum from dept_use_dtl t1 " +
                        "where  use_id = '" + workOrder.getRefId() + "' and supplier_id='" + workOrder.getSupplierId() + "' and flag_consignment='" + flagConsignment + "' and  flag_omoc='" + flagOmoc + "' ";
                break;
            case WorkOrderType.OPRT_USE: //病人消耗模块、HIS接口消耗
                sumSql = " select ifnull(sum(t1.sku_qty),0) as qtysum from dept_oprt_use_item t1 " +
                        "where  dept_oprt_use_id = '" + workOrder.getRefId() + "' and supplier_id='" + workOrder.getSupplierId() + "' and flag_consignment='" + flagConsignment + "' and flag_omoc='" + flagOmoc + "' ";
                break;
            case WorkOrderType.IN_OPRT_RED: //病人消耗模块、HIS退费或者病人消耗冲红
                sumSql = " select ifnull(sum(t1.sku_qty),0) as qtysum from dept_oprt_use_item t1 " +
                        "where  dept_oprt_use_id = '" + workOrder.getRefId() + "' and supplier_id='" + workOrder.getSupplierId() + "' and flag_consignment='" + flagConsignment + "' and flag_omoc='" + flagOmoc + "' ";
                break;
        }
        if (sumSql != null) {
            try {
                skuQtyBusSum = UtilNum.getDouble(jdbcTemplate.queryForObject(sumSql, String.class));
            } catch (EmptyResultDataAccessException e) {
            } catch (Exception e) {
                logger.error("_checkWorkOrder.error", e);
            }

            if (skuQtyBusSum != skuQtySum)
                throw new BusinessException("出入库表校验失败！出入库数量【%s】与业务单据数量【%s】不一致，请稍候重试", skuQtySum, skuQtyBusSum);
        }

        double itemAmount = 0d;
        double sum;
        if (WorkOrderItems != null && WorkOrderItems.size() > 0) {
            List<String> stockIdList = WorkOrderItems.stream().map(WorkOrderItem::getStockId).collect(Collectors.toList());
            List<Stock> stockList = null;
            if (workOrder.getBusType().equals(WorkOrderType.IN_DEPT_RETURN)
                    || workOrder.getBusType().equals(WorkOrderType.IN_USE_RED)
                    || workOrder.getBusType().equals(WorkOrderType.IN_OPRT_RED)
            ) { //需要查询0库存  科室退货入库，科室消耗 冲红入库，病人消耗模块、HIS退费或者病人消耗冲红
                stockList = StockCommonService.listStockWithZero(Wrappers.<Stock>query().in("id", stockIdList), null);
            } else {
                stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIdList));
            }
            for (WorkOrderItem ob : WorkOrderItems) {
                //单品数量*单品价格 是否等于 合计金额
                sum = UtilNum.mul(ob.getSkuPrice(), ob.getSkuQty());
                if (Math.abs(sum) != Math.abs(ob.getAmount()))
                    throw new BusinessException("出入库表校验失败！<br>工作记录明细表金额【" + ob.getAmount() + "】不等于单品数量*单品价格金额【" + sum + "】");

                //忽略非包装耗材
                if (StringUtils.isBlank(ob.getMatrType()) || !"0".equalsIgnoreCase(ob.getMatrType())) {
                    //itsmAmount[0] = UtilNum.sum(itsmAmount[0],ob.getAmount());
                    return;
                }
                ;

                //校验跟库存中的供应商是否一致
                List<Stock> stockListFind = stockList.stream().filter(stockTmp -> stockTmp.getId().equals(ob.getStockId())).collect(Collectors.toList());
                Stock stockFind = null;
                if (stockListFind != null && stockListFind.size() > 0) stockFind = stockListFind.get(0);
                if (stockFind != null && !stockFind.getSupplierId().equals(workOrder.getSupplierId()))
                    throw new BusinessException("出入库表校验失败！<br>主表供应商【%s】与库存供应商【%s】不一致", workOrder.getSupplierName(), stockFind.getSupplierName());

                //检查耗材单品单位是否一致
                Matr matr = matrService.getById(ob.getMatrId());
                if (matr == null) throw new BusinessException("出入库表校验失败！<br>耗材【" + ob.getMatrName() + "】已删除或者不存在");
                if (!matr.getSkuUnit().equals(ob.getSkuUnit()))
                    throw new BusinessException("出入库表校验失败！<br>耗材单品单位【" + matr.getSkuUnit() + "】与明细单品单位【" + ob.getSkuUnit() + "】不一致");
//            if(!matr.getSkuPrice().equals(ob.getSkuPrice()))  throw new BusinessException("出入库表校验失败！<br>耗材单品价格【"+matr.getSkuPrice()+"】与明细单品价格"+ob.getSkuPrice()+"不一致");

                //检查耗材包装单位转换是否有问题
               /* List<MatrUnit> matrUnits = matrUnitService.list(Wrappers.<MatrUnit>query().eq("matr_id", ob.getMatrId()).eq("unit", ob.getPackageUnit()));
                if (matrUnits == null || matrUnits.size() < 1)
                    throw new BusinessException("出入库表校验失败！<br>未找到耗材【" + ob.getMatrName() + "】包装单位【" + ob.getPackageUnit() + "】，请联系运营人员检查耗材属性");
                if (matrUnits.size() > 1)
                    throw new BusinessException("出入库表校验失败！<br>耗材【" + ob.getMatrName() + "】找到多个包装单位【" + ob.getPackageUnit() + "】，请联系运营人员检查耗材属性");

                sum = UtilNum.mul(ob.getPackageQty(), matrUnits.get(0).getRate());
                if (
                        !workOrder.getBusType().equals(WorkOrderType.IN_DEPT_RETURN)
                        && !workOrder.getBusType().equals(WorkOrderType.IN_USE_RED)
                                && Math.abs(sum) != Math.abs(ob.getSkuQty())

                ){
                    throw new BusinessException("出入库表校验失败，包装单位转换错误！<br>包装单位：" + ob.getPackageUnit() + "，包装数量：" + ob.getPackageQty() + "，包装转换率：" + matrUnits.get(0).getRate() + "，实际单品数量：" + ob.getSkuQty());
                }*/

//            sum[0] = UtilNum.mul(ob.getPackageQty(),matrUnits.get(0).getRate() * ob.getSkuPrice());
//            if(Math.abs(sum[0]) != Math.abs(UtilNum.getDouble(ob.getAmount()))) throw new BusinessException("出入库表校验失败，包装单位转换错误！<br>包装单位："+ob.getPackageUnit()+"，包装数量："+ob.getPackageQty()+"，包装转换率："+matrUnits.get(0).getRate()+"，单品价格："+ob.getSkuPrice()+"，实际单品数量："+ob.getSkuQty());

                itemAmount = UtilNum.sum(itemAmount, ob.getAmount());
            }
        }
        if (Math.abs(itemAmount) != Math.abs(UtilNum.getDouble(workOrder.getAmount())))
            throw new BusinessException("出入库表校验失败！<br>工作记录表主表金额【" + workOrder.getAmount() + "】不等于明细表累计金额【" + itemAmount + "】");
    }


    @Override
    public List<Stock> addStockBatchForPack(WorkOrder workOrder, List<WorkOrderItem> workOrderItemList) {

        //按照入库明细包装数量数据汇总，生成条码 (有小数的明细 自动向上取整)
        double sumBarCodeCount = workOrderItemList.stream().mapToDouble(item-> Math.ceil(item.getPackageQty())).sum();

//                if (sumBarCodeCount != Double.valueOf(sumBarCodeCount).intValue()) {
//                    throw new BusinessException("SN生成校验失败，入库包装数量必须为整数！");
//                }
        int snCount = Integer.parseInt(UtilNum.getString(sumBarCodeCount));
        List<String> snList = serialRuleAdapter.getSerialRuleService().batchGenerateCode(SerialKeys.WM_STOCK_PROCESS_SN, snCount);
        int snNumber = 0;
        List<OrderBarcode> barcodeList= new ArrayList<>();
        List<Stock> stockList= new ArrayList<>();
        Stock stock = null;
        for (WorkOrderItem workOrderItem : workOrderItemList) {
//                    明细存在小数的向上取整
            double ceilCount = Math.ceil(workOrderItem.getPackageQty());
            int packageCount = Integer.parseInt(UtilNum.getString(ceilCount));
            for (int i = 0; i < packageCount; i++) {
                double packageQty = 1D;
                if ((UtilNum.sub(workOrderItem.getPackageQty(), (double) i) < 1D)) {
                    packageQty = UtilNum.sub(workOrderItem.getPackageQty(), (double) i);
                }
                OrderBarcode orderBarcode = new OrderBarcode(workOrderItem.getWorkOrderId(), workOrderItem.getId(), workOrderItem.getSn(),
                        workOrderItem.getRfid(),
                        workOrderItem.getUdi(),packageQty);
                orderBarcode.setSn(snList.get(snNumber));
                barcodeList.add(orderBarcode);
                snNumber++;

                stock = new Stock();
                BeanUtils.copyProperties(workOrderItem, stock, "id");
                stock.setSupplierId(workOrder.getSupplierId())
                        .setSupplierName(workOrder.getSupplierName())
                        .setWarehouseId(workOrder.getWarehouseId())
                        .setWarehouseName(workOrder.getWarehouseName())
                        .setFlagConsignment(workOrder.getFlagConsignment())
                        .setFlagOmoc(workOrder.getFlagOmoc())
                        .setPackageQty(1d);
                stock.setFlagUniqueCode(true);
                //一物一码的也有可能选择包装单位
                stock.setSkuQty(workOrderItem.getSkuQty() / workOrderItem.getPackageQty());
                stock.setSkuPrice(workOrderItem.getSkuPrice());
                stock.setAmount(stock.getSkuQty() * stock.getSkuPrice());
                stock.setFlagTemporaryPurchase(workOrderItem.getFlagTemporaryPurchase());

                stock.setSn(orderBarcode.getSn());
                stock.setInTime(new Date());
                stockList.add(stock);
            }
        }
        orderBarcodeService.saveOrUpdateBatch(barcodeList);
        stockService.saveOrUpdateBatch(stockList);

        return stockList;
    }
}
